#ifndef REGEXP_H
#define REGEXP_H

#include "mstl.h"

unsigned char parseEscapeChar(unsigned char c, const unsigned char *&s);

inline int hexDigitToValue(unsigned char c)
{
	if (c>='0' && c<='9') return c-'0';
	else if (c>='A' && c<='F') return c-('A'-10);
	else if (c>='a' && c<='f') return c-('a'-10);
	else return -1;
}

namespace RE
{
using namespace MSTL;

//#define REGEXP_DEBUG
#ifdef REGEXP_DEBUG
#define RE_DBG(x) x
#else
#define RE_DBG(x)
#endif

class Context;
extern class FuncAlways // always true
{
public:
  virtual bool doit(Context &c);
  virtual void undo(Context &c);
  RE_DBG(virtual const char *getName();)
} funcAlways;

typedef FuncAlways Func;

struct Match
{ int m_pos, m_len;
  List<String> m_regs;
  Match(int pos, int len, List<String> &regs, bool once=false) : m_pos(pos), m_len(len), m_regs(regs) {}
};

struct State;
struct Transition
{
  State *m_next;
  Func *m_func;
  Transition(State *next, Func *func);
  void changeNext(State *next);
  inline static void changeFirst(State *&first, State *newState);
  inline static void setFirst(State *&first, State *newState);
};

struct State: public List<Transition> 
{
  int m_useCount;
  State(): List<Transition>(), m_useCount(0) {}
  void insert(int index, State *next, Func *f=&funcAlways);
  bool isUseless() { return length()==1 && (*this)->m_func==&funcAlways; }
};

inline void Transition::setFirst(State *&first, State *newState)
{
	first = newState;
	if (first)
		first->m_useCount++;
}

inline void Transition::changeFirst(State *&first, State *newState)
{
	if (first)
		first->m_useCount--;
	setFirst(first,newState);
}

class Expr
{
  void simplify();
public:
  String m_expr;
  int m_mask; // i:0x1, m:0x2, o:0x4
  State *m_first;
  List<State> m_states;
  List<Func> m_funcs;
  State *convert     ( const unsigned char *&s, State *&last, bool isFirst );
  State *orOpConvert ( const unsigned char *&s, State *&last, bool isFirst );
  Expr(unsigned char *str, int len, int mask);
  void parse();
  unsigned char getChar(const unsigned char *&s);
  String toTyle() const
  { int i=2+(m_mask&1)+((m_mask>>1)&1)+((m_mask>>2)&1)+m_expr.length();
    String r(i);
    unsigned char *p=r;
    *(p++)='`';
    memcpy(p,(unsigned char *)m_expr,m_expr.length()); 
    p+=m_expr.length();
    *(p++)='`';
    if (m_mask&1) *(p++)='i';    
    if (m_mask&2) *(p++)='m';    
    if (m_mask&4) *(p++)='o';    
    return r;
  }
  static void convertString(char *o, const char *i, const char *ie);
  Expr(Expr *left, String right,bool isLiteral);
  void match(List<Match>::P matches, const unsigned char *s, int len, bool once=false);
  inline static unsigned char uncaps(unsigned char c)
  { return c>='A' && c<='Z' ? c+('a'-'A') : c;
  }

  ~Expr();
};

}
#endif
